import json
import re

from django.contrib.auth import login
from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
from QQLoginTool.QQtool import OAuthQQ
# 使用Django 的settings方法获取配置文件中的数据
from django.conf import settings
from django_redis import get_redis_connection
# 导入加密模块
from itsdangerous import TimedJSONWebSignatureSerializer
from apps.carts.utils import megre_cart
from apps.oauth.models import OAuthQQUser
from apps.users.models import User


# Create your views here.
class QQLoginUrlView(View):
    """
        构建生成qq跳转链接
    """

    def get(self, request):
        # 1、初始化生成qq对象
        QQ = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                     redirect_uri=settings.QQ_REDIRECT_URI, state=None)

        # 2、使用QQ对象生成跳转链接
        login_url = QQ.get_qq_url()

        return JsonResponse({'code': 0, 'login_url': login_url, 'errmsg': 'ok'})


class OauthBackView(View):

    def get(self, request):
        # 1、获取code数据，是查询字符串形式
        code = request.GET.get('code')
        if code is None:
            return JsonResponse({"code": 400, 'errmsg': '缺少code参数'}, status=400)
        # 2、根据code数据获取access_token
        QQ = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                     redirect_uri=settings.QQ_REDIRECT_URI, state=None)
        access_token = QQ.get_access_token(code)
        # 3、根据access_token数据获取openid
        openid = QQ.get_open_id(access_token)

        # 4、判断oepnid是都绑定过美多用户，查询QQ表进行判断是否绑定
        try:
            # 如果根据openid查询到数据，则说明以前存储过数据，和美多用已经进行过绑定，该用户可以直接进行登录。
            qq = OAuthQQUser.objects.get(openid=openid)
        except:
            # 捕获到异常，说明get放没有查询到数据，则该openid没有存储过，则需要进行用户绑定
            # 需要对openid进行加密
            tjs = TimedJSONWebSignatureSerializer(settings.SECRET_KEY, 300)
            # 加密后的数据是bytes，返回前端时需要转化为字符串数据
            openid_token = tjs.dumps({'openid': openid}).decode()
            return JsonResponse({'code': 300, 'access_token': openid_token})

        # 没有异常，则进行登录操作，需要状态保持 需要在cookie写入用户名
        user = qq.user  # OAuthQQUser关联美多用户外键user
        login(request, user)  # user 是美多用户
        response = JsonResponse({'code': 0})
        response.set_cookie('username', user.username)
        # 合并购物车
        response = megre_cart(request, response, user)
        return response

    def post(self, request):

        # 1、接受前端传递的json数据 是bytes类型数据
        json_data = request.body.decode()
        # 2、将json转化字典数据
        dict_data = json.loads(json_data)
        # 3、从字典中提取相关的字段数据  dict_data['username'] 数据不存在抛出异常
        mobile = dict_data.get('mobile')
        password = dict_data.get('password')
        sms_code = dict_data.get('sms_code')  # 前端用户输入的短信数据
        # 获取加密的opedid数据
        access_token = dict_data.get('access_token')
        # 解密操作
        tjs = TimedJSONWebSignatureSerializer(settings.SECRET_KEY, 300)
        try:
            oepnid_dict = tjs.loads(access_token)
        except:
            # 解密失败
            return JsonResponse({'code': 400, 'errmsg': '无效的openid值'}, status=400)
        # 提取openid
        openid = oepnid_dict.get('openid')

        # 4、验证字段数据
        # 4-1、验证数据完整性all方法中如果有空值会返回false
        if not all([mobile, password, sms_code]):
            return JsonResponse({'code': 400, 'errmsg': '参数不完整'}, status=400)
        # 4-2、判断手机号格式
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号格式不正确'}, status=400)
        # 4-3、判断密码格式
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式不正确'}, status=400)
        # 4-4、短信验证判断
        # 连接redis
        conn = get_redis_connection('verify')
        # 获取reids中存储的短信验证码
        real_code = conn.get('sms_code_%s' % mobile)
        # 判断real_code是否超过有效期
        if real_code is None:
            return JsonResponse({'code': 400, 'errmsg': '验证码失效'}, status=400)
        # 判断用户输入的短信验证码和redis中的是否一致
        if sms_code != real_code.decode():
            return JsonResponse({'code': 400, 'errmsg': '验证码输入错误'}, status=400)

        # 5、将数据保存在数据库中，将用户和opendi保存在一起进行绑定
        # 5-1 获取保存的数据用户user和openid
        try:
            user = User.objects.get(mobile=mobile)
        except:
            # 捕获到异常说明手机号没有注册过美多用户，使用该手机号注册一个新用户
            user = User.objects.create_user(username=mobile, mobile=mobile, password=password)

        # 5-2 将用户和openID进行保存
        OAuthQQUser.objects.create(user=user, openid=openid)
        # 绑定成功，需要进行状态保持,第一个参数request对象,第二个参数是用户对象
        login(request, user)
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username)
        # 合并购物车
        response = megre_cart(request, response, user)
        # 6、返回结果
        return response
